import cv2
import numpy as np
import edgeDetection as edge
import matplotlib.pyplot as plt
# Load the image (test1)
filename = 'test1.jpg'
imgbgr = cv2.imread(filename)
origImageSize = imgbgr.shape[::-1][1:]
imgrgb = cv2.cvtColor(imgbgr, cv2.COLOR_BGR2RGB)
plt.imshow(imgrgb)
plt.show()
# change the image to binary color only black and white
hls = cv2.cvtColor(imgbgr, cv2.COLOR_BGR2HLS)
_, sxbinary = edge.threshold(hls[:, :, 1], thresh=(180, 255))
sxbinary = edge.blurGaussian(sxbinary, ksize=3)
sxbinary = edge.magThresh(sxbinary, sobelKernel=3, thresh=(110, 255))
sChannel = hls[:, :, 2]
_, sBinary = edge.threshold(sChannel, (150, 255))
_, rThresh = edge.threshold(imgbgr[:, :, 2], thresh=(200, 255))
rsBinary = cv2.bitwise_and(sBinary, rThresh)
laneLineMarkings = cv2.bitwise_or(rsBinary, sxbinary.astype(np.uint8))
plt.imshow(cv2.cvtColor(laneLineMarkings, cv2.COLOR_BGR2RGB))
plt.show()
# Place the region of interest (ROI) on the image
roiPoints = np.float32([
(570,460),
(213,684),
(1120,680),
(715,460)
])
imgbgrCopy = imgbgr.copy()
thisImage = cv2.polylines(imgbgrCopy, np.int32([roiPoints]), True, (147,20,255), 3)
plt.imshow(cv2.cvtColor(thisImage, cv2.COLOR_BGR2RGB))
plt.show()
desiredRoiPoints = np.float32([
[320, 0],
[320, origImageSize[1]],
[origImageSize[0]-320, origImageSize[1]],
[origImageSize[0]-320, 0]
])
transformationMatrix = cv2.getPerspectiveTransform(roiPoints, desiredRoiPoints)
invTransformationMatrix = cv2.getPerspectiveTransform(desiredRoiPoints, roiPoints)
warpedFrame = cv2.warpPerspective(laneLineMarkings, transformationMatrix, origImageSize, flags=(cv2.INTER_LINEAR))
(thresh, binaryWarped) = cv2.threshold(warpedFrame, 127, 255, cv2.THRESH_BINARY)
warpedFrame = binaryWarped.copy()
warpedPlot = cv2.polylines(binaryWarped, np.int32([desiredRoiPoints]), True, (147,20,255), 3)
plt.imshow(cv2.cvtColor(warpedPlot, cv2.COLOR_BGR2RGB))
plt.show()
histogram = np.sum(warpedFrame[int(warpedFrame.shape[0]/2):,:], axis=0)
figure, (ax1, ax2) = plt.subplots(2,1) # 2 row, 1 columns
figure.set_size_inches(10, 5)
ax1.imshow(warpedFrame, cmap='gray')
ax1.set_title("Warped Binary Frame")
ax2.plot(histogram)
ax2.set_title("Histogram Peaks")
plt.show()
# Get the indices of the lane line pixels using the sliding windows technique
margin = int((1/12) * origImageSize[0])
noOfWindows = 10
frameSlidingWindow = warpedFrame.copy()
windowHeight = np.int(warpedFrame.shape[0]/noOfWindows)
nonzero = warpedFrame.nonzero()
nonzeroy = np.array(nonzero[0])
nonzerox = np.array(nonzero[1])
leftLaneInds = []
rightLaneInds = []
midpoint = np.int(histogram.shape[0]/2)
leftxBase = np.argmax(histogram[:midpoint])
rightxBase = np.argmax(histogram[midpoint:]) + midpoint
leftxCurrent = leftxBase
rightxCurrent = rightxBase
for window in range(noOfWindows):
winYLow = warpedFrame.shape[0] - (window + 1) * windowHeight
winYHigh = warpedFrame.shape[0] - window * windowHeight
winXleftLow = leftxCurrent - margin
winXleftHigh = leftxCurrent + margin
winXrightLow = rightxCurrent - margin
winXrightHigh = rightxCurrent + margin
cv2.rectangle(frameSlidingWindow,(winXleftLow,winYLow),(winXleftHigh,winYHigh), (255,255,255), 2)
cv2.rectangle(frameSlidingWindow,(winXrightLow,winYLow),(winXrightHigh,winYHigh), (255,255,255), 2)
goodLeftInds = ((nonzeroy >= winYLow) & (nonzeroy < winYHigh) & (nonzerox >= winXleftLow) & (
nonzerox < winXleftHigh)).nonzero()[0]
goodRightInds = ((nonzeroy >= winYLow) & (nonzeroy < winYHigh) & (nonzerox >= winXrightLow) & (
nonzerox < winXrightHigh)).nonzero()[0]
leftLaneInds.append(goodLeftInds)
rightLaneInds.append(goodRightInds)
minpix = int((1/24) * origImageSize[0])
if len(goodLeftInds) > minpix:
leftxCurrent = np.int(np.mean(nonzerox[goodLeftInds]))
if len(goodRightInds) > minpix:
rightxCurrent = np.int(np.mean(nonzerox[goodRightInds]))
leftLaneInds = np.concatenate(leftLaneInds)
rightLaneInds = np.concatenate(rightLaneInds)
leftx = nonzerox[leftLaneInds]
lefty = nonzeroy[leftLaneInds]
rightx = nonzerox[rightLaneInds]
righty = nonzeroy[rightLaneInds]
leftFit = np.polyfit(lefty, leftx, 2)
rightFit = np.polyfit(righty, rightx, 2)
ploty = np.linspace(0, frameSlidingWindow.shape[0]-1, warpedFrame.shape[0])
leftFitx = leftFit[0]*ploty**2 + leftFit[1]*ploty + leftFit[2]
rightFitx = rightFit[0]*ploty**2 + rightFit[1]*ploty + rightFit[2]
outImg = np.dstack((frameSlidingWindow, frameSlidingWindow, (frameSlidingWindow))) * 255
outImg[nonzeroy[leftLaneInds], nonzerox[leftLaneInds]] = [255, 0, 0]
outImg[nonzeroy[rightLaneInds], nonzerox[rightLaneInds]] = [0, 0, 255]
figure, (ax1, ax2, ax3) = plt.subplots(3,1)
figure.set_size_inches(10, 10)
figure.tight_layout(pad=3.0)
ax1.imshow(imgrgb)
ax2.imshow(frameSlidingWindow, cmap='gray')
ax3.imshow(outImg)
ax3.plot(leftFitx, ploty, color='yellow')
ax3.plot(rightFitx, ploty, color='yellow')
ax1.set_title("Original Frame")
ax2.set_title("Warped Frame with Sliding Windows")
ax3.set_title("Detected Lane Lines with Sliding Windows")
plt.show()
# Use the lane line from the previous sliding window to get the parameters for the polynomial line for filling in the lane line
leftLaneInds = ((nonzerox > (leftFit[0]*(nonzeroy**2) + leftFit[1]*nonzeroy + leftFit[2] - margin)) & (nonzerox < (leftFit[0]*(
nonzeroy**2) + leftFit[1]*nonzeroy + leftFit[2] + margin)))
rightLaneInds = ((nonzerox > (rightFit[0]*(nonzeroy**2) + rightFit[1]*nonzeroy + rightFit[2] - margin)) & (nonzerox <
(rightFit[0]*(nonzeroy**2) + rightFit[1]*nonzeroy + rightFit[2] + margin)))
leftx = nonzerox[leftLaneInds]
lefty = nonzeroy[leftLaneInds]
rightx = nonzerox[rightLaneInds]
righty = nonzeroy[rightLaneInds]
leftFit = np.polyfit(lefty, leftx, 2)
rightFit = np.polyfit(righty, rightx, 2)
ploty = np.linspace(0, warpedFrame.shape[0]-1, warpedFrame.shape[0])
leftFitx = leftFit[0]*ploty**2 + leftFit[1]*ploty + leftFit[2]
rightFitx = rightFit[0]*ploty**2 + rightFit[1]*ploty + rightFit[2]
outImg = np.dstack((warpedFrame, warpedFrame, (warpedFrame)))*255
windowImg = np.zeros_like(outImg)
outImg[nonzeroy[leftLaneInds], nonzerox[leftLaneInds]] = [255, 0, 0]
outImg[nonzeroy[rightLaneInds], nonzerox[rightLaneInds]] = [0, 0, 255]
leftLineWindow1 = np.array([np.transpose(np.vstack([leftFitx-margin, ploty]))])
leftLineWindow2 = np.array([np.flipud(np.transpose(np.vstack([leftFitx+margin, ploty])))])
leftLinePts = np.hstack((leftLineWindow1, leftLineWindow2))
rightLineWindow1 = np.array([np.transpose(np.vstack([rightFitx-margin, ploty]))])
rightLineWindow2 = np.array([np.flipud(np.transpose(np.vstack([rightFitx+margin, ploty])))])
rightLinePts = np.hstack((rightLineWindow1, rightLineWindow2))
cv2.fillPoly(windowImg, np.int_([leftLinePts]), (0,255, 0))
cv2.fillPoly(windowImg, np.int_([rightLinePts]), (0,255, 0))
result = cv2.addWeighted(outImg, 1, windowImg, 0.3, 0)
figure, (ax1, ax2, ax3) = plt.subplots(3,1)
figure.set_size_inches(10, 10)
figure.tight_layout(pad=3.0)
ax1.imshow(imgrgb)
ax2.imshow(warpedFrame, cmap='gray')
ax3.imshow(result)
ax3.plot(leftFitx, ploty, color='yellow')
ax3.plot(rightFitx, ploty, color='yellow')
ax1.set_title("Original Frame")
ax2.set_title("Warped Frame")
ax3.set_title("Warped Frame With Search Window")
plt.show()
# Overlay lane lines on the original frame
warpZero = np.zeros_like(warpedFrame).astype(np.uint8)
colorWarp = np.dstack((warpZero, warpZero, warpZero))
ptsLeft = np.array([np.transpose(np.vstack([leftFitx, ploty]))])
ptsRight = np.array([np.flipud(np.transpose(np.vstack([rightFitx, ploty])))])
pts = np.hstack((ptsLeft, ptsRight))
cv2.fillPoly(colorWarp, np.int_([pts]), (0,255, 0))
newwarp = cv2.warpPerspective(colorWarp, invTransformationMatrix, (imgbgr.shape[1], imgbgr.shape[0]))
result = cv2.addWeighted(imgbgr, 1, newwarp, 0.3, 0)
figure, (ax1, ax2) = plt.subplots(2,1) # 2 rows, 1 column
figure.set_size_inches(10, 10)
figure.tight_layout(pad=3.0)
ax1.imshow(cv2.cvtColor(imgbgr, cv2.COLOR_BGR2RGB))
ax2.imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
ax1.set_title("Original Frame")
ax2.set_title("Original Frame With Lane Overlay")
plt.show()
# Calculate the road curvature in meters.
YMPERPIX = 10.0 / 1000
XMPERPIX = 3.7 / 781
yEval = np.max(ploty)
leftFitCr = np.polyfit(lefty * YMPERPIX, leftx * (XMPERPIX), 2)
rightFitCr = np.polyfit(righty * YMPERPIX, rightx * (XMPERPIX), 2)
leftCurvem = ((1 + (2*leftFitCr[0]*yEval*YMPERPIX + leftFitCr[1])**2)**1.5) / np.absolute(2*leftFitCr[0])
rightCurvem = ((1 + (2*rightFitCr[0]*yEval*YMPERPIX + rightFitCr[1])**2)**1.5) / np.absolute(2*rightFitCr[0])
print(f"Left lane curvature= {leftCurvem}m.")
print(f"Right lane curvature= {rightCurvem}m.")
print(f"The radius of curvature= {(leftCurvem+rightCurvem)/2}m.")
Left lane curvature= 73.85407120102911m. Right lane curvature= 360.20847907101887m. The radius of curvature= 217.031275136024m.
# Calculate the position of the car relative to the center
carLocation = imgbgr.shape[1] / 2
height = imgbgr.shape[0]
bottomLeft = leftFit[0]*height**2 + leftFit[1]*height + leftFit[2]
bottomRight = rightFit[0]*height**2 + rightFit[1]*height + rightFit[2]
centerLane = (bottomRight - bottomLeft)/2 + bottomLeft
centerOffset = (np.abs(carLocation) - np.abs(centerLane)) * XMPERPIX
offsetStr = ""
if (centerOffset < 0):
offsetStr = "left of center"
elif (centerOffset > 0):
offsetStr = "right of center"
print(f"Center offset= {np.abs(centerOffset)}m {offsetStr}.")
Center offset= 0.08157021388077526m left of center.
# Display curvature and offset statistics on the image (Final image to be shown)
finalVersion = result.copy()
cv2.putText(finalVersion,'Curve Radius: '+str((leftCurvem+rightCurvem)/2)[:7]+'m', (int((5/600)*origImageSize[0]), int((
20/338)*origImageSize[1])), cv2.FONT_HERSHEY_SIMPLEX, (float((0.5/600)*origImageSize[0])),(255,255,255),2,cv2.LINE_AA)
offsetStr = ""
if (centerOffset < 0):
offsetStr = " Left of Center"
elif (centerOffset > 0):
offsetStr = " Right of Center"
cv2.putText(finalVersion,'Center Offset: '+str(np.abs(centerOffset))[:7]+'m'+offsetStr, (int((5/600)*origImageSize[0]), int((
40/338)*origImageSize[1])), cv2.FONT_HERSHEY_SIMPLEX, (float((0.5/600)*origImageSize[0])),(255,255,255),2,cv2.LINE_AA)
plt.imshow(cv2.cvtColor(finalVersion, cv2.COLOR_BGR2RGB))
plt.show()
# Load the image (test2)
filename = 'test2.jpg'
imgbgr = cv2.imread(filename)
origImageSize = imgbgr.shape[::-1][1:]
imgrgb = cv2.cvtColor(imgbgr, cv2.COLOR_BGR2RGB)
plt.imshow(imgrgb)
plt.show()
# change the image to binary color only black and white
hls = cv2.cvtColor(imgbgr, cv2.COLOR_BGR2HLS)
_, sxbinary = edge.threshold(hls[:, :, 1], thresh=(180, 255))
sxbinary = edge.blurGaussian(sxbinary, ksize=3)
sxbinary = edge.magThresh(sxbinary, sobelKernel=3, thresh=(110, 255))
sChannel = hls[:, :, 2]
_, sBinary = edge.threshold(sChannel, (20, 255))
_, rThresh = edge.threshold(imgbgr[:, :, 2], thresh=(180, 255))
rsBinary = cv2.bitwise_and(sBinary, rThresh)
laneLineMarkings = cv2.bitwise_or(rsBinary, sxbinary.astype(np.uint8))
plt.imshow(cv2.cvtColor(laneLineMarkings, cv2.COLOR_BGR2RGB))
plt.show()
# Place the region of interest (ROI) on the image
roiPoints = np.float32([
(570,460),
(213,684),
(1120,680),
(715,460)
])
imgbgrCopy = imgbgr.copy()
thisImage = cv2.polylines(imgbgrCopy, np.int32([roiPoints]), True, (147,20,255), 3)
plt.imshow(cv2.cvtColor(thisImage, cv2.COLOR_BGR2RGB))
plt.show()
desiredRoiPoints = np.float32([
[320, 0],
[320, origImageSize[1]],
[origImageSize[0]-320, origImageSize[1]],
[origImageSize[0]-320, 0]
])
transformationMatrix = cv2.getPerspectiveTransform(roiPoints, desiredRoiPoints)
invTransformationMatrix = cv2.getPerspectiveTransform(desiredRoiPoints, roiPoints)
warpedFrame = cv2.warpPerspective(laneLineMarkings, transformationMatrix, origImageSize, flags=(cv2.INTER_LINEAR))
(thresh, binaryWarped) = cv2.threshold(warpedFrame, 127, 255, cv2.THRESH_BINARY)
warpedFrame = binaryWarped.copy()
warpedPlot = cv2.polylines(binaryWarped, np.int32([desiredRoiPoints]), True, (147,20,255), 3)
plt.imshow(cv2.cvtColor(warpedPlot, cv2.COLOR_BGR2RGB))
plt.show()
histogram = np.sum(warpedFrame[int(warpedFrame.shape[0]/2):,:], axis=0)
figure, (ax1, ax2) = plt.subplots(2,1) # 2 row, 1 columns
figure.set_size_inches(10, 5)
ax1.imshow(warpedFrame, cmap='gray')
ax1.set_title("Warped Binary Frame")
ax2.plot(histogram)
ax2.set_title("Histogram Peaks")
plt.show()
# Get the indices of the lane line pixels using the sliding windows technique
margin = int((1/12) * origImageSize[0])
noOfWindows = 10
frameSlidingWindow = warpedFrame.copy()
windowHeight = np.int(warpedFrame.shape[0]/noOfWindows)
nonzero = warpedFrame.nonzero()
nonzeroy = np.array(nonzero[0])
nonzerox = np.array(nonzero[1])
leftLaneInds = []
rightLaneInds = []
midpoint = np.int(histogram.shape[0]/2)
leftxBase = np.argmax(histogram[:midpoint])
rightxBase = np.argmax(histogram[midpoint:]) + midpoint
leftxCurrent = leftxBase
rightxCurrent = rightxBase
for window in range(noOfWindows):
winYLow = warpedFrame.shape[0] - (window + 1) * windowHeight
winYHigh = warpedFrame.shape[0] - window * windowHeight
winXleftLow = leftxCurrent - margin
winXleftHigh = leftxCurrent + margin
winXrightLow = rightxCurrent - margin
winXrightHigh = rightxCurrent + margin
cv2.rectangle(frameSlidingWindow,(winXleftLow,winYLow),(winXleftHigh,winYHigh), (255,255,255), 2)
cv2.rectangle(frameSlidingWindow,(winXrightLow,winYLow),(winXrightHigh,winYHigh), (255,255,255), 2)
goodLeftInds = ((nonzeroy >= winYLow) & (nonzeroy < winYHigh) & (nonzerox >= winXleftLow) & (
nonzerox < winXleftHigh)).nonzero()[0]
goodRightInds = ((nonzeroy >= winYLow) & (nonzeroy < winYHigh) & (nonzerox >= winXrightLow) & (
nonzerox < winXrightHigh)).nonzero()[0]
leftLaneInds.append(goodLeftInds)
rightLaneInds.append(goodRightInds)
minpix = int((1/24) * origImageSize[0])
if len(goodLeftInds) > minpix:
leftxCurrent = np.int(np.mean(nonzerox[goodLeftInds]))
if len(goodRightInds) > minpix:
rightxCurrent = np.int(np.mean(nonzerox[goodRightInds]))
leftLaneInds = np.concatenate(leftLaneInds)
rightLaneInds = np.concatenate(rightLaneInds)
leftx = nonzerox[leftLaneInds]
lefty = nonzeroy[leftLaneInds]
rightx = nonzerox[rightLaneInds]
righty = nonzeroy[rightLaneInds]
leftFit = np.polyfit(lefty, leftx, 2)
rightFit = np.polyfit(righty, rightx, 2)
ploty = np.linspace(0, frameSlidingWindow.shape[0]-1, warpedFrame.shape[0])
leftFitx = leftFit[0]*ploty**2 + leftFit[1]*ploty + leftFit[2]
rightFitx = rightFit[0]*ploty**2 + rightFit[1]*ploty + rightFit[2]
outImg = np.dstack((frameSlidingWindow, frameSlidingWindow, (frameSlidingWindow))) * 255
outImg[nonzeroy[leftLaneInds], nonzerox[leftLaneInds]] = [255, 0, 0]
outImg[nonzeroy[rightLaneInds], nonzerox[rightLaneInds]] = [0, 0, 255]
figure, (ax1, ax2, ax3) = plt.subplots(3,1)
figure.set_size_inches(10, 10)
figure.tight_layout(pad=3.0)
ax1.imshow(imgrgb)
ax2.imshow(frameSlidingWindow, cmap='gray')
ax3.imshow(outImg)
ax3.plot(leftFitx, ploty, color='yellow')
ax3.plot(rightFitx, ploty, color='yellow')
ax1.set_title("Original Frame")
ax2.set_title("Warped Frame with Sliding Windows")
ax3.set_title("Detected Lane Lines with Sliding Windows")
plt.show()
# Use the lane line from the previous sliding window to get the parameters for the polynomial line for filling in the lane line
leftLaneInds = ((nonzerox > (leftFit[0]*(nonzeroy**2) + leftFit[1]*nonzeroy + leftFit[2] - margin)) & (nonzerox < (leftFit[0]*(
nonzeroy**2) + leftFit[1]*nonzeroy + leftFit[2] + margin)))
rightLaneInds = ((nonzerox > (rightFit[0]*(nonzeroy**2) + rightFit[1]*nonzeroy + rightFit[2] - margin)) & (nonzerox <
(rightFit[0]*(nonzeroy**2) + rightFit[1]*nonzeroy + rightFit[2] + margin)))
leftx = nonzerox[leftLaneInds]
lefty = nonzeroy[leftLaneInds]
rightx = nonzerox[rightLaneInds]
righty = nonzeroy[rightLaneInds]
leftFit = np.polyfit(lefty, leftx, 2)
rightFit = np.polyfit(righty, rightx, 2)
ploty = np.linspace(0, warpedFrame.shape[0]-1, warpedFrame.shape[0])
leftFitx = leftFit[0]*ploty**2 + leftFit[1]*ploty + leftFit[2]
rightFitx = rightFit[0]*ploty**2 + rightFit[1]*ploty + rightFit[2]
outImg = np.dstack((warpedFrame, warpedFrame, (warpedFrame)))*255
windowImg = np.zeros_like(outImg)
outImg[nonzeroy[leftLaneInds], nonzerox[leftLaneInds]] = [255, 0, 0]
outImg[nonzeroy[rightLaneInds], nonzerox[rightLaneInds]] = [0, 0, 255]
leftLineWindow1 = np.array([np.transpose(np.vstack([leftFitx-margin, ploty]))])
leftLineWindow2 = np.array([np.flipud(np.transpose(np.vstack([leftFitx+margin, ploty])))])
leftLinePts = np.hstack((leftLineWindow1, leftLineWindow2))
rightLineWindow1 = np.array([np.transpose(np.vstack([rightFitx-margin, ploty]))])
rightLineWindow2 = np.array([np.flipud(np.transpose(np.vstack([rightFitx+margin, ploty])))])
rightLinePts = np.hstack((rightLineWindow1, rightLineWindow2))
cv2.fillPoly(windowImg, np.int_([leftLinePts]), (0,255, 0))
cv2.fillPoly(windowImg, np.int_([rightLinePts]), (0,255, 0))
result = cv2.addWeighted(outImg, 1, windowImg, 0.3, 0)
figure, (ax1, ax2, ax3) = plt.subplots(3,1)
figure.set_size_inches(10, 10)
figure.tight_layout(pad=3.0)
ax1.imshow(imgrgb)
ax2.imshow(warpedFrame, cmap='gray')
ax3.imshow(result)
ax3.plot(leftFitx, ploty, color='yellow')
ax3.plot(rightFitx, ploty, color='yellow')
ax1.set_title("Original Frame")
ax2.set_title("Warped Frame")
ax3.set_title("Warped Frame With Search Window")
plt.show()
# Overlay lane lines on the original frame
warpZero = np.zeros_like(warpedFrame).astype(np.uint8)
colorWarp = np.dstack((warpZero, warpZero, warpZero))
ptsLeft = np.array([np.transpose(np.vstack([leftFitx, ploty]))])
ptsRight = np.array([np.flipud(np.transpose(np.vstack([rightFitx, ploty])))])
pts = np.hstack((ptsLeft, ptsRight))
cv2.fillPoly(colorWarp, np.int_([pts]), (0,255, 0))
newwarp = cv2.warpPerspective(colorWarp, invTransformationMatrix, (imgbgr.shape[1], imgbgr.shape[0]))
result = cv2.addWeighted(imgbgr, 1, newwarp, 0.3, 0)
figure, (ax1, ax2) = plt.subplots(2,1) # 2 rows, 1 column
figure.set_size_inches(10, 10)
figure.tight_layout(pad=3.0)
ax1.imshow(cv2.cvtColor(imgbgr, cv2.COLOR_BGR2RGB))
ax2.imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
ax1.set_title("Original Frame")
ax2.set_title("Original Frame With Lane Overlay")
plt.show()
# Calculate the road curvature in meters.
YMPERPIX = 10.0 / 1000
XMPERPIX = 3.7 / 781
yEval = np.max(ploty)
leftFitCr = np.polyfit(lefty * YMPERPIX, leftx * (XMPERPIX), 2)
rightFitCr = np.polyfit(righty * YMPERPIX, rightx * (XMPERPIX), 2)
leftCurvem = ((1 + (2*leftFitCr[0]*yEval*YMPERPIX + leftFitCr[1])**2)**1.5) / np.absolute(2*leftFitCr[0])
rightCurvem = ((1 + (2*rightFitCr[0]*yEval*YMPERPIX + rightFitCr[1])**2)**1.5) / np.absolute(2*rightFitCr[0])
print(f"Left lane curvature= {leftCurvem}m.")
print(f"Right lane curvature= {rightCurvem}m.")
print(f"The radius of curvature= {(leftCurvem+rightCurvem)/2}m.")
Left lane curvature= 55.30488630363746m. Right lane curvature= 176.838395155925m. The radius of curvature= 116.07164072978124m.
# Calculate the position of the car relative to the center
carLocation = imgbgr.shape[1] / 2
height = imgbgr.shape[0]
bottomLeft = leftFit[0]*height**2 + leftFit[1]*height + leftFit[2]
bottomRight = rightFit[0]*height**2 + rightFit[1]*height + rightFit[2]
centerLane = (bottomRight - bottomLeft)/2 + bottomLeft
centerOffset = (np.abs(carLocation) - np.abs(centerLane)) * XMPERPIX
offsetStr = ""
if (centerOffset < 0):
offsetStr = "left of center"
elif (centerOffset > 0):
offsetStr = "right of center"
print(f"Center offset= {np.abs(centerOffset)}m {offsetStr}.")
Center offset= 0.2345157968154317m left of center.
# Display curvature and offset statistics on the image (Final image to be shown)
finalVersion = result.copy()
cv2.putText(finalVersion,'Curve Radius: '+str((leftCurvem+rightCurvem)/2)[:7]+'m', (int((5/600)*origImageSize[0]), int((
20/338)*origImageSize[1])), cv2.FONT_HERSHEY_SIMPLEX, (float((0.5/600)*origImageSize[0])),(255,255,255),2,cv2.LINE_AA)
offsetStr = ""
if (centerOffset < 0):
offsetStr = " Left of Center"
elif (centerOffset > 0):
offsetStr = " Right of Center"
cv2.putText(finalVersion,'Center Offset: '+str(np.abs(centerOffset))[:7]+'m'+offsetStr, (int((5/600)*origImageSize[0]), int((
40/338)*origImageSize[1])), cv2.FONT_HERSHEY_SIMPLEX, (float((0.5/600)*origImageSize[0])),(255,255,255),2,cv2.LINE_AA)
plt.imshow(cv2.cvtColor(finalVersion, cv2.COLOR_BGR2RGB))
plt.show()
# Load the image (test3)
filename = 'test3.jpg'
imgbgr = cv2.imread(filename)
origImageSize = imgbgr.shape[::-1][1:]
imgrgb = cv2.cvtColor(imgbgr, cv2.COLOR_BGR2RGB)
plt.imshow(imgrgb)
plt.show()
# change the image to binary color only black and white
hls = cv2.cvtColor(imgbgr, cv2.COLOR_BGR2HLS)
_, sxbinary = edge.threshold(hls[:, :, 1], thresh=(180, 255))
sxbinary = edge.blurGaussian(sxbinary, ksize=3)
sxbinary = edge.magThresh(sxbinary, sobelKernel=3, thresh=(110, 255))
sChannel = hls[:, :, 2]
_, sBinary = edge.threshold(sChannel, (20, 255))
_, rThresh = edge.threshold(imgbgr[:, :, 2], thresh=(180, 255))
rsBinary = cv2.bitwise_and(sBinary, rThresh)
laneLineMarkings = cv2.bitwise_or(rsBinary, sxbinary.astype(np.uint8))
plt.imshow(cv2.cvtColor(laneLineMarkings, cv2.COLOR_BGR2RGB))
plt.show()
# Place the region of interest (ROI) on the image
roiPoints = np.float32([
(570,460),
(213,684),
(1120,680),
(715,460)
])
imgbgrCopy = imgbgr.copy()
thisImage = cv2.polylines(imgbgrCopy, np.int32([roiPoints]), True, (147,20,255), 3)
plt.imshow(cv2.cvtColor(thisImage, cv2.COLOR_BGR2RGB))
plt.show()
desiredRoiPoints = np.float32([
[320, 0],
[320, origImageSize[1]],
[origImageSize[0]-320, origImageSize[1]],
[origImageSize[0]-320, 0]
])
transformationMatrix = cv2.getPerspectiveTransform(roiPoints, desiredRoiPoints)
invTransformationMatrix = cv2.getPerspectiveTransform(desiredRoiPoints, roiPoints)
warpedFrame = cv2.warpPerspective(laneLineMarkings, transformationMatrix, origImageSize, flags=(cv2.INTER_LINEAR))
(thresh, binaryWarped) = cv2.threshold(warpedFrame, 127, 255, cv2.THRESH_BINARY)
warpedFrame = binaryWarped.copy()
warpedPlot = cv2.polylines(binaryWarped, np.int32([desiredRoiPoints]), True, (147,20,255), 3)
plt.imshow(cv2.cvtColor(warpedPlot, cv2.COLOR_BGR2RGB))
plt.show()
histogram = np.sum(warpedFrame[int(warpedFrame.shape[0]/2):,:], axis=0)
figure, (ax1, ax2) = plt.subplots(2,1) # 2 row, 1 columns
figure.set_size_inches(10, 5)
ax1.imshow(warpedFrame, cmap='gray')
ax1.set_title("Warped Binary Frame")
ax2.plot(histogram)
ax2.set_title("Histogram Peaks")
plt.show()
# Get the indices of the lane line pixels using the sliding windows technique
margin = int((1/12) * origImageSize[0])
noOfWindows = 10
frameSlidingWindow = warpedFrame.copy()
windowHeight = np.int(warpedFrame.shape[0]/noOfWindows)
nonzero = warpedFrame.nonzero()
nonzeroy = np.array(nonzero[0])
nonzerox = np.array(nonzero[1])
leftLaneInds = []
rightLaneInds = []
midpoint = np.int(histogram.shape[0]/2)
leftxBase = np.argmax(histogram[:midpoint])
rightxBase = np.argmax(histogram[midpoint:]) + midpoint
leftxCurrent = leftxBase
rightxCurrent = rightxBase
for window in range(noOfWindows):
winYLow = warpedFrame.shape[0] - (window + 1) * windowHeight
winYHigh = warpedFrame.shape[0] - window * windowHeight
winXleftLow = leftxCurrent - margin
winXleftHigh = leftxCurrent + margin
winXrightLow = rightxCurrent - margin
winXrightHigh = rightxCurrent + margin
cv2.rectangle(frameSlidingWindow,(winXleftLow,winYLow),(winXleftHigh,winYHigh), (255,255,255), 2)
cv2.rectangle(frameSlidingWindow,(winXrightLow,winYLow),(winXrightHigh,winYHigh), (255,255,255), 2)
goodLeftInds = ((nonzeroy >= winYLow) & (nonzeroy < winYHigh) & (nonzerox >= winXleftLow) & (
nonzerox < winXleftHigh)).nonzero()[0]
goodRightInds = ((nonzeroy >= winYLow) & (nonzeroy < winYHigh) & (nonzerox >= winXrightLow) & (
nonzerox < winXrightHigh)).nonzero()[0]
leftLaneInds.append(goodLeftInds)
rightLaneInds.append(goodRightInds)
minpix = int((1/24) * origImageSize[0])
if len(goodLeftInds) > minpix:
leftxCurrent = np.int(np.mean(nonzerox[goodLeftInds]))
if len(goodRightInds) > minpix:
rightxCurrent = np.int(np.mean(nonzerox[goodRightInds]))
leftLaneInds = np.concatenate(leftLaneInds)
rightLaneInds = np.concatenate(rightLaneInds)
leftx = nonzerox[leftLaneInds]
lefty = nonzeroy[leftLaneInds]
rightx = nonzerox[rightLaneInds]
righty = nonzeroy[rightLaneInds]
leftFit = np.polyfit(lefty, leftx, 2)
rightFit = np.polyfit(righty, rightx, 2)
ploty = np.linspace(0, frameSlidingWindow.shape[0]-1, warpedFrame.shape[0])
leftFitx = leftFit[0]*ploty**2 + leftFit[1]*ploty + leftFit[2]
rightFitx = rightFit[0]*ploty**2 + rightFit[1]*ploty + rightFit[2]
outImg = np.dstack((frameSlidingWindow, frameSlidingWindow, (frameSlidingWindow))) * 255
outImg[nonzeroy[leftLaneInds], nonzerox[leftLaneInds]] = [255, 0, 0]
outImg[nonzeroy[rightLaneInds], nonzerox[rightLaneInds]] = [0, 0, 255]
figure, (ax1, ax2, ax3) = plt.subplots(3,1)
figure.set_size_inches(10, 10)
figure.tight_layout(pad=3.0)
ax1.imshow(imgrgb)
ax2.imshow(frameSlidingWindow, cmap='gray')
ax3.imshow(outImg)
ax3.plot(leftFitx, ploty, color='yellow')
ax3.plot(rightFitx, ploty, color='yellow')
ax1.set_title("Original Frame")
ax2.set_title("Warped Frame with Sliding Windows")
ax3.set_title("Detected Lane Lines with Sliding Windows")
plt.show()
# Use the lane line from the previous sliding window to get the parameters for the polynomial line for filling in the lane line
leftLaneInds = ((nonzerox > (leftFit[0]*(nonzeroy**2) + leftFit[1]*nonzeroy + leftFit[2] - margin)) & (nonzerox < (leftFit[0]*(
nonzeroy**2) + leftFit[1]*nonzeroy + leftFit[2] + margin)))
rightLaneInds = ((nonzerox > (rightFit[0]*(nonzeroy**2) + rightFit[1]*nonzeroy + rightFit[2] - margin)) & (nonzerox <
(rightFit[0]*(nonzeroy**2) + rightFit[1]*nonzeroy + rightFit[2] + margin)))
leftx = nonzerox[leftLaneInds]
lefty = nonzeroy[leftLaneInds]
rightx = nonzerox[rightLaneInds]
righty = nonzeroy[rightLaneInds]
leftFit = np.polyfit(lefty, leftx, 2)
rightFit = np.polyfit(righty, rightx, 2)
ploty = np.linspace(0, warpedFrame.shape[0]-1, warpedFrame.shape[0])
leftFitx = leftFit[0]*ploty**2 + leftFit[1]*ploty + leftFit[2]
rightFitx = rightFit[0]*ploty**2 + rightFit[1]*ploty + rightFit[2]
outImg = np.dstack((warpedFrame, warpedFrame, (warpedFrame)))*255
windowImg = np.zeros_like(outImg)
outImg[nonzeroy[leftLaneInds], nonzerox[leftLaneInds]] = [255, 0, 0]
outImg[nonzeroy[rightLaneInds], nonzerox[rightLaneInds]] = [0, 0, 255]
leftLineWindow1 = np.array([np.transpose(np.vstack([leftFitx-margin, ploty]))])
leftLineWindow2 = np.array([np.flipud(np.transpose(np.vstack([leftFitx+margin, ploty])))])
leftLinePts = np.hstack((leftLineWindow1, leftLineWindow2))
rightLineWindow1 = np.array([np.transpose(np.vstack([rightFitx-margin, ploty]))])
rightLineWindow2 = np.array([np.flipud(np.transpose(np.vstack([rightFitx+margin, ploty])))])
rightLinePts = np.hstack((rightLineWindow1, rightLineWindow2))
cv2.fillPoly(windowImg, np.int_([leftLinePts]), (0,255, 0))
cv2.fillPoly(windowImg, np.int_([rightLinePts]), (0,255, 0))
result = cv2.addWeighted(outImg, 1, windowImg, 0.3, 0)
figure, (ax1, ax2, ax3) = plt.subplots(3,1)
figure.set_size_inches(10, 10)
figure.tight_layout(pad=3.0)
ax1.imshow(imgrgb)
ax2.imshow(warpedFrame, cmap='gray')
ax3.imshow(result)
ax3.plot(leftFitx, ploty, color='yellow')
ax3.plot(rightFitx, ploty, color='yellow')
ax1.set_title("Original Frame")
ax2.set_title("Warped Frame")
ax3.set_title("Warped Frame With Search Window")
plt.show()
# Overlay lane lines on the original frame
warpZero = np.zeros_like(warpedFrame).astype(np.uint8)
colorWarp = np.dstack((warpZero, warpZero, warpZero))
ptsLeft = np.array([np.transpose(np.vstack([leftFitx, ploty]))])
ptsRight = np.array([np.flipud(np.transpose(np.vstack([rightFitx, ploty])))])
pts = np.hstack((ptsLeft, ptsRight))
cv2.fillPoly(colorWarp, np.int_([pts]), (0,255, 0))
newwarp = cv2.warpPerspective(colorWarp, invTransformationMatrix, (imgbgr.shape[1], imgbgr.shape[0]))
result = cv2.addWeighted(imgbgr, 1, newwarp, 0.3, 0)
figure, (ax1, ax2) = plt.subplots(2,1) # 2 rows, 1 column
figure.set_size_inches(10, 10)
figure.tight_layout(pad=3.0)
ax1.imshow(cv2.cvtColor(imgbgr, cv2.COLOR_BGR2RGB))
ax2.imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
ax1.set_title("Original Frame")
ax2.set_title("Original Frame With Lane Overlay")
plt.show()
# Calculate the road curvature in meters.
YMPERPIX = 10.0 / 1000
XMPERPIX = 3.7 / 781
yEval = np.max(ploty)
leftFitCr = np.polyfit(lefty * YMPERPIX, leftx * (XMPERPIX), 2)
rightFitCr = np.polyfit(righty * YMPERPIX, rightx * (XMPERPIX), 2)
leftCurvem = ((1 + (2*leftFitCr[0]*yEval*YMPERPIX + leftFitCr[1])**2)**1.5) / np.absolute(2*leftFitCr[0])
rightCurvem = ((1 + (2*rightFitCr[0]*yEval*YMPERPIX + rightFitCr[1])**2)**1.5) / np.absolute(2*rightFitCr[0])
print(f"Left lane curvature= {leftCurvem}m.")
print(f"Right lane curvature= {rightCurvem}m.")
print(f"The radius of curvature= {(leftCurvem+rightCurvem)/2}m.")
Left lane curvature= 113.28306411403085m. Right lane curvature= 67.93562202314271m. The radius of curvature= 90.60934306858678m.
# Calculate the position of the car relative to the center
carLocation = imgbgr.shape[1] / 2
height = imgbgr.shape[0]
bottomLeft = leftFit[0]*height**2 + leftFit[1]*height + leftFit[2]
bottomRight = rightFit[0]*height**2 + rightFit[1]*height + rightFit[2]
centerLane = (bottomRight - bottomLeft)/2 + bottomLeft
centerOffset = (np.abs(carLocation) - np.abs(centerLane)) * XMPERPIX
offsetStr = ""
if (centerOffset < 0):
offsetStr = "left of center"
elif (centerOffset > 0):
offsetStr = "right of center"
print(f"Center offset= {np.abs(centerOffset)}m {offsetStr}.")
Center offset= 0.045937314055673945m left of center.
# Display curvature and offset statistics on the image (Final image to be shown)
finalVersion = result.copy()
cv2.putText(finalVersion,'Curve Radius: '+str((leftCurvem+rightCurvem)/2)[:7]+'m', (int((5/600)*origImageSize[0]), int((
20/338)*origImageSize[1])), cv2.FONT_HERSHEY_SIMPLEX, (float((0.5/600)*origImageSize[0])),(255,255,255),2,cv2.LINE_AA)
offsetStr = ""
if (centerOffset < 0):
offsetStr = " Left of Center"
elif (centerOffset > 0):
offsetStr = " Right of Center"
cv2.putText(finalVersion,'Center Offset: '+str(np.abs(centerOffset))[:7]+'m'+offsetStr, (int((5/600)*origImageSize[0]), int((
40/338)*origImageSize[1])), cv2.FONT_HERSHEY_SIMPLEX, (float((0.5/600)*origImageSize[0])),(255,255,255),2,cv2.LINE_AA)
plt.imshow(cv2.cvtColor(finalVersion, cv2.COLOR_BGR2RGB))
plt.show()
# Load the image (test4)
filename = 'test4.jpg'
imgbgr = cv2.imread(filename)
origImageSize = imgbgr.shape[::-1][1:]
imgrgb = cv2.cvtColor(imgbgr, cv2.COLOR_BGR2RGB)
plt.imshow(imgrgb)
plt.show()
# change the image to binary color only black and white
hls = cv2.cvtColor(imgbgr, cv2.COLOR_BGR2HLS)
_, sxbinary = edge.threshold(hls[:, :, 1], thresh=(180, 255))
sxbinary = edge.blurGaussian(sxbinary, ksize=3)
sxbinary = edge.magThresh(sxbinary, sobelKernel=3, thresh=(110, 255))
sChannel = hls[:, :, 2]
_, sBinary = edge.threshold(sChannel, (140, 255))
_, rThresh = edge.threshold(imgbgr[:, :, 2], thresh=(220, 255))
rsBinary = cv2.bitwise_and(sBinary, rThresh)
laneLineMarkings = cv2.bitwise_or(rsBinary, sxbinary.astype(np.uint8))
plt.imshow(cv2.cvtColor(laneLineMarkings, cv2.COLOR_BGR2RGB))
plt.show()
# Place the region of interest (ROI) on the image
roiPoints = np.float32([
(570,460),
(213,684),
(1120,680),
(715,460)
])
imgbgrCopy = imgbgr.copy()
thisImage = cv2.polylines(imgbgrCopy, np.int32([roiPoints]), True, (147,20,255), 3)
plt.imshow(cv2.cvtColor(thisImage, cv2.COLOR_BGR2RGB))
plt.show()
desiredRoiPoints = np.float32([
[320, 0],
[320, origImageSize[1]],
[origImageSize[0]-320, origImageSize[1]],
[origImageSize[0]-320, 0]
])
transformationMatrix = cv2.getPerspectiveTransform(roiPoints, desiredRoiPoints)
invTransformationMatrix = cv2.getPerspectiveTransform(desiredRoiPoints, roiPoints)
warpedFrame = cv2.warpPerspective(laneLineMarkings, transformationMatrix, origImageSize, flags=(cv2.INTER_LINEAR))
(thresh, binaryWarped) = cv2.threshold(warpedFrame, 127, 255, cv2.THRESH_BINARY)
warpedFrame = binaryWarped.copy()
warpedPlot = cv2.polylines(binaryWarped, np.int32([desiredRoiPoints]), True, (147,20,255), 3)
plt.imshow(cv2.cvtColor(warpedPlot, cv2.COLOR_BGR2RGB))
plt.show()
histogram = np.sum(warpedFrame[int(warpedFrame.shape[0]/2):,:], axis=0)
figure, (ax1, ax2) = plt.subplots(2,1) # 2 row, 1 columns
figure.set_size_inches(10, 5)
ax1.imshow(warpedFrame, cmap='gray')
ax1.set_title("Warped Binary Frame")
ax2.plot(histogram)
ax2.set_title("Histogram Peaks")
plt.show()
# Get the indices of the lane line pixels using the sliding windows technique
margin = int((1/12) * origImageSize[0])
noOfWindows = 10
frameSlidingWindow = warpedFrame.copy()
windowHeight = np.int(warpedFrame.shape[0]/noOfWindows)
nonzero = warpedFrame.nonzero()
nonzeroy = np.array(nonzero[0])
nonzerox = np.array(nonzero[1])
leftLaneInds = []
rightLaneInds = []
midpoint = np.int(histogram.shape[0]/2)
leftxBase = np.argmax(histogram[:midpoint])
rightxBase = np.argmax(histogram[midpoint:]) + midpoint
leftxCurrent = leftxBase
rightxCurrent = rightxBase
for window in range(noOfWindows):
winYLow = warpedFrame.shape[0] - (window + 1) * windowHeight
winYHigh = warpedFrame.shape[0] - window * windowHeight
winXleftLow = leftxCurrent - margin
winXleftHigh = leftxCurrent + margin
winXrightLow = rightxCurrent - margin
winXrightHigh = rightxCurrent + margin
cv2.rectangle(frameSlidingWindow,(winXleftLow,winYLow),(winXleftHigh,winYHigh), (255,255,255), 2)
cv2.rectangle(frameSlidingWindow,(winXrightLow,winYLow),(winXrightHigh,winYHigh), (255,255,255), 2)
goodLeftInds = ((nonzeroy >= winYLow) & (nonzeroy < winYHigh) & (nonzerox >= winXleftLow) & (
nonzerox < winXleftHigh)).nonzero()[0]
goodRightInds = ((nonzeroy >= winYLow) & (nonzeroy < winYHigh) & (nonzerox >= winXrightLow) & (
nonzerox < winXrightHigh)).nonzero()[0]
leftLaneInds.append(goodLeftInds)
rightLaneInds.append(goodRightInds)
minpix = int((1/24) * origImageSize[0])
if len(goodLeftInds) > minpix:
leftxCurrent = np.int(np.mean(nonzerox[goodLeftInds]))
if len(goodRightInds) > minpix:
rightxCurrent = np.int(np.mean(nonzerox[goodRightInds]))
leftLaneInds = np.concatenate(leftLaneInds)
rightLaneInds = np.concatenate(rightLaneInds)
leftx = nonzerox[leftLaneInds]
lefty = nonzeroy[leftLaneInds]
rightx = nonzerox[rightLaneInds]
righty = nonzeroy[rightLaneInds]
leftFit = np.polyfit(lefty, leftx, 2)
rightFit = np.polyfit(righty, rightx, 2)
ploty = np.linspace(0, frameSlidingWindow.shape[0]-1, warpedFrame.shape[0])
leftFitx = leftFit[0]*ploty**2 + leftFit[1]*ploty + leftFit[2]
rightFitx = rightFit[0]*ploty**2 + rightFit[1]*ploty + rightFit[2]
outImg = np.dstack((frameSlidingWindow, frameSlidingWindow, (frameSlidingWindow))) * 255
outImg[nonzeroy[leftLaneInds], nonzerox[leftLaneInds]] = [255, 0, 0]
outImg[nonzeroy[rightLaneInds], nonzerox[rightLaneInds]] = [0, 0, 255]
figure, (ax1, ax2, ax3) = plt.subplots(3,1)
figure.set_size_inches(10, 10)
figure.tight_layout(pad=3.0)
ax1.imshow(imgrgb)
ax2.imshow(frameSlidingWindow, cmap='gray')
ax3.imshow(outImg)
ax3.plot(leftFitx, ploty, color='yellow')
ax3.plot(rightFitx, ploty, color='yellow')
ax1.set_title("Original Frame")
ax2.set_title("Warped Frame with Sliding Windows")
ax3.set_title("Detected Lane Lines with Sliding Windows")
plt.show()
# Use the lane line from the previous sliding window to get the parameters for the polynomial line for filling in the lane line
leftLaneInds = ((nonzerox > (leftFit[0]*(nonzeroy**2) + leftFit[1]*nonzeroy + leftFit[2] - margin)) & (nonzerox < (leftFit[0]*(
nonzeroy**2) + leftFit[1]*nonzeroy + leftFit[2] + margin)))
rightLaneInds = ((nonzerox > (rightFit[0]*(nonzeroy**2) + rightFit[1]*nonzeroy + rightFit[2] - margin)) & (nonzerox <
(rightFit[0]*(nonzeroy**2) + rightFit[1]*nonzeroy + rightFit[2] + margin)))
leftx = nonzerox[leftLaneInds]
lefty = nonzeroy[leftLaneInds]
rightx = nonzerox[rightLaneInds]
righty = nonzeroy[rightLaneInds]
leftFit = np.polyfit(lefty, leftx, 2)
rightFit = np.polyfit(righty, rightx, 2)
ploty = np.linspace(0, warpedFrame.shape[0]-1, warpedFrame.shape[0])
leftFitx = leftFit[0]*ploty**2 + leftFit[1]*ploty + leftFit[2]
rightFitx = rightFit[0]*ploty**2 + rightFit[1]*ploty + rightFit[2]
outImg = np.dstack((warpedFrame, warpedFrame, (warpedFrame)))*255
windowImg = np.zeros_like(outImg)
outImg[nonzeroy[leftLaneInds], nonzerox[leftLaneInds]] = [255, 0, 0]
outImg[nonzeroy[rightLaneInds], nonzerox[rightLaneInds]] = [0, 0, 255]
leftLineWindow1 = np.array([np.transpose(np.vstack([leftFitx-margin, ploty]))])
leftLineWindow2 = np.array([np.flipud(np.transpose(np.vstack([leftFitx+margin, ploty])))])
leftLinePts = np.hstack((leftLineWindow1, leftLineWindow2))
rightLineWindow1 = np.array([np.transpose(np.vstack([rightFitx-margin, ploty]))])
rightLineWindow2 = np.array([np.flipud(np.transpose(np.vstack([rightFitx+margin, ploty])))])
rightLinePts = np.hstack((rightLineWindow1, rightLineWindow2))
cv2.fillPoly(windowImg, np.int_([leftLinePts]), (0,255, 0))
cv2.fillPoly(windowImg, np.int_([rightLinePts]), (0,255, 0))
result = cv2.addWeighted(outImg, 1, windowImg, 0.3, 0)
figure, (ax1, ax2, ax3) = plt.subplots(3,1)
figure.set_size_inches(10, 10)
figure.tight_layout(pad=3.0)
ax1.imshow(imgrgb)
ax2.imshow(warpedFrame, cmap='gray')
ax3.imshow(result)
ax3.plot(leftFitx, ploty, color='yellow')
ax3.plot(rightFitx, ploty, color='yellow')
ax1.set_title("Original Frame")
ax2.set_title("Warped Frame")
ax3.set_title("Warped Frame With Search Window")
plt.show()
# Overlay lane lines on the original frame
warpZero = np.zeros_like(warpedFrame).astype(np.uint8)
colorWarp = np.dstack((warpZero, warpZero, warpZero))
ptsLeft = np.array([np.transpose(np.vstack([leftFitx, ploty]))])
ptsRight = np.array([np.flipud(np.transpose(np.vstack([rightFitx, ploty])))])
pts = np.hstack((ptsLeft, ptsRight))
cv2.fillPoly(colorWarp, np.int_([pts]), (0,255, 0))
newwarp = cv2.warpPerspective(colorWarp, invTransformationMatrix, (imgbgr.shape[1], imgbgr.shape[0]))
result = cv2.addWeighted(imgbgr, 1, newwarp, 0.3, 0)
figure, (ax1, ax2) = plt.subplots(2,1) # 2 rows, 1 column
figure.set_size_inches(10, 10)
figure.tight_layout(pad=3.0)
ax1.imshow(cv2.cvtColor(imgbgr, cv2.COLOR_BGR2RGB))
ax2.imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
ax1.set_title("Original Frame")
ax2.set_title("Original Frame With Lane Overlay")
plt.show()
# Calculate the road curvature in meters.
YMPERPIX = 10.0 / 1000
XMPERPIX = 3.7 / 781
yEval = np.max(ploty)
leftFitCr = np.polyfit(lefty * YMPERPIX, leftx * (XMPERPIX), 2)
rightFitCr = np.polyfit(righty * YMPERPIX, rightx * (XMPERPIX), 2)
leftCurvem = ((1 + (2*leftFitCr[0]*yEval*YMPERPIX + leftFitCr[1])**2)**1.5) / np.absolute(2*leftFitCr[0])
rightCurvem = ((1 + (2*rightFitCr[0]*yEval*YMPERPIX + rightFitCr[1])**2)**1.5) / np.absolute(2*rightFitCr[0])
print(f"Left lane curvature= {leftCurvem}m.")
print(f"Right lane curvature= {rightCurvem}m.")
print(f"The radius of curvature= {(leftCurvem+rightCurvem)/2}m.")
Left lane curvature= 87.14333689358263m. Right lane curvature= 65.02973691086348m. The radius of curvature= 76.08653690222306m.
# Calculate the position of the car relative to the center
carLocation = imgbgr.shape[1] / 2
height = imgbgr.shape[0]
bottomLeft = leftFit[0]*height**2 + leftFit[1]*height + leftFit[2]
bottomRight = rightFit[0]*height**2 + rightFit[1]*height + rightFit[2]
centerLane = (bottomRight - bottomLeft)/2 + bottomLeft
centerOffset = (np.abs(carLocation) - np.abs(centerLane)) * XMPERPIX
offsetStr = ""
if (centerOffset < 0):
offsetStr = "left of center"
elif (centerOffset > 0):
offsetStr = "right of center"
print(f"Center offset= {np.abs(centerOffset)}m {offsetStr}.")
Center offset= 0.17112796593483726m left of center.
# Display curvature and offset statistics on the image (Final image to be shown)
finalVersion = result.copy()
cv2.putText(finalVersion,'Curve Radius: '+str((leftCurvem+rightCurvem)/2)[:7]+'m', (int((5/600)*origImageSize[0]), int((
20/338)*origImageSize[1])), cv2.FONT_HERSHEY_SIMPLEX, (float((0.5/600)*origImageSize[0])),(255,255,255),2,cv2.LINE_AA)
offsetStr = ""
if (centerOffset < 0):
offsetStr = " Left of Center"
elif (centerOffset > 0):
offsetStr = " Right of Center"
cv2.putText(finalVersion,'Center Offset: '+str(np.abs(centerOffset))[:7]+'m'+offsetStr, (int((5/600)*origImageSize[0]), int((
40/338)*origImageSize[1])), cv2.FONT_HERSHEY_SIMPLEX, (float((0.5/600)*origImageSize[0])),(255,255,255),2,cv2.LINE_AA)
plt.imshow(cv2.cvtColor(finalVersion, cv2.COLOR_BGR2RGB))
plt.show()
# Load the image (test5)
filename = 'test5.jpg'
imgbgr = cv2.imread(filename)
origImageSize = imgbgr.shape[::-1][1:]
imgrgb = cv2.cvtColor(imgbgr, cv2.COLOR_BGR2RGB)
plt.imshow(imgrgb)
plt.show()
# change the image to binary color only black and white
hls = cv2.cvtColor(imgbgr, cv2.COLOR_BGR2HLS)
_, sxbinary = edge.threshold(hls[:, :, 1], thresh=(230, 255))
sxbinary = edge.blurGaussian(sxbinary, ksize=3)
sxbinary = edge.magThresh(sxbinary, sobelKernel=3, thresh=(110, 255))
sChannel = hls[:, :, 2]
_, sBinary = edge.threshold(sChannel, (80, 255))
_, rThresh = edge.threshold(imgbgr[:, :, 2], thresh=(150, 255))
rsBinary = cv2.bitwise_and(sBinary, rThresh)
laneLineMarkings = cv2.bitwise_or(rsBinary, sxbinary.astype(np.uint8))
plt.imshow(cv2.cvtColor(laneLineMarkings, cv2.COLOR_BGR2RGB))
plt.show()
# Place the region of interest (ROI) on the image
roiPoints = np.float32([
(570,460),
(213,684),
(1120,680),
(715,460)
])
imgbgrCopy = imgbgr.copy()
thisImage = cv2.polylines(imgbgrCopy, np.int32([roiPoints]), True, (147,20,255), 3)
plt.imshow(cv2.cvtColor(thisImage, cv2.COLOR_BGR2RGB))
plt.show()
desiredRoiPoints = np.float32([
[320, 0],
[320, origImageSize[1]],
[origImageSize[0]-320, origImageSize[1]],
[origImageSize[0]-320, 0]
])
transformationMatrix = cv2.getPerspectiveTransform(roiPoints, desiredRoiPoints)
invTransformationMatrix = cv2.getPerspectiveTransform(desiredRoiPoints, roiPoints)
warpedFrame = cv2.warpPerspective(laneLineMarkings, transformationMatrix, origImageSize, flags=(cv2.INTER_LINEAR))
(thresh, binaryWarped) = cv2.threshold(warpedFrame, 127, 255, cv2.THRESH_BINARY)
warpedFrame = binaryWarped.copy()
warpedPlot = cv2.polylines(binaryWarped, np.int32([desiredRoiPoints]), True, (147,20,255), 3)
plt.imshow(cv2.cvtColor(warpedPlot, cv2.COLOR_BGR2RGB))
plt.show()
histogram = np.sum(warpedFrame[int(warpedFrame.shape[0]/2):,:], axis=0)
figure, (ax1, ax2) = plt.subplots(2,1) # 2 row, 1 columns
figure.set_size_inches(10, 5)
ax1.imshow(warpedFrame, cmap='gray')
ax1.set_title("Warped Binary Frame")
ax2.plot(histogram)
ax2.set_title("Histogram Peaks")
plt.show()
# Get the indices of the lane line pixels using the sliding windows technique
margin = int((1/12) * origImageSize[0])
noOfWindows = 10
frameSlidingWindow = warpedFrame.copy()
windowHeight = np.int(warpedFrame.shape[0]/noOfWindows)
nonzero = warpedFrame.nonzero()
nonzeroy = np.array(nonzero[0])
nonzerox = np.array(nonzero[1])
leftLaneInds = []
rightLaneInds = []
midpoint = np.int(histogram.shape[0]/2)
leftxBase = np.argmax(histogram[:midpoint])
rightxBase = np.argmax(histogram[midpoint:]) + midpoint
leftxCurrent = leftxBase
rightxCurrent = rightxBase
for window in range(noOfWindows):
winYLow = warpedFrame.shape[0] - (window + 1) * windowHeight
winYHigh = warpedFrame.shape[0] - window * windowHeight
winXleftLow = leftxCurrent - margin
winXleftHigh = leftxCurrent + margin
winXrightLow = rightxCurrent - margin
winXrightHigh = rightxCurrent + margin
cv2.rectangle(frameSlidingWindow,(winXleftLow,winYLow),(winXleftHigh,winYHigh), (255,255,255), 2)
cv2.rectangle(frameSlidingWindow,(winXrightLow,winYLow),(winXrightHigh,winYHigh), (255,255,255), 2)
goodLeftInds = ((nonzeroy >= winYLow) & (nonzeroy < winYHigh) & (nonzerox >= winXleftLow) & (
nonzerox < winXleftHigh)).nonzero()[0]
goodRightInds = ((nonzeroy >= winYLow) & (nonzeroy < winYHigh) & (nonzerox >= winXrightLow) & (
nonzerox < winXrightHigh)).nonzero()[0]
leftLaneInds.append(goodLeftInds)
rightLaneInds.append(goodRightInds)
minpix = int((1/24) * origImageSize[0])
if len(goodLeftInds) > minpix:
leftxCurrent = np.int(np.mean(nonzerox[goodLeftInds]))
if len(goodRightInds) > minpix:
rightxCurrent = np.int(np.mean(nonzerox[goodRightInds]))
leftLaneInds = np.concatenate(leftLaneInds)
rightLaneInds = np.concatenate(rightLaneInds)
leftx = nonzerox[leftLaneInds]
lefty = nonzeroy[leftLaneInds]
rightx = nonzerox[rightLaneInds]
righty = nonzeroy[rightLaneInds]
leftFit = np.polyfit(lefty, leftx, 2)
rightFit = np.polyfit(righty, rightx, 2)
ploty = np.linspace(0, frameSlidingWindow.shape[0]-1, warpedFrame.shape[0])
leftFitx = leftFit[0]*ploty**2 + leftFit[1]*ploty + leftFit[2]
rightFitx = rightFit[0]*ploty**2 + rightFit[1]*ploty + rightFit[2]
outImg = np.dstack((frameSlidingWindow, frameSlidingWindow, (frameSlidingWindow))) * 255
outImg[nonzeroy[leftLaneInds], nonzerox[leftLaneInds]] = [255, 0, 0]
outImg[nonzeroy[rightLaneInds], nonzerox[rightLaneInds]] = [0, 0, 255]
figure, (ax1, ax2, ax3) = plt.subplots(3,1)
figure.set_size_inches(10, 10)
figure.tight_layout(pad=3.0)
ax1.imshow(imgrgb)
ax2.imshow(frameSlidingWindow, cmap='gray')
ax3.imshow(outImg)
ax3.plot(leftFitx, ploty, color='yellow')
ax3.plot(rightFitx, ploty, color='yellow')
ax1.set_title("Original Frame")
ax2.set_title("Warped Frame with Sliding Windows")
ax3.set_title("Detected Lane Lines with Sliding Windows")
plt.show()
# Use the lane line from the previous sliding window to get the parameters for the polynomial line for filling in the lane line
leftLaneInds = ((nonzerox > (leftFit[0]*(nonzeroy**2) + leftFit[1]*nonzeroy + leftFit[2] - margin)) & (nonzerox < (leftFit[0]*(
nonzeroy**2) + leftFit[1]*nonzeroy + leftFit[2] + margin)))
rightLaneInds = ((nonzerox > (rightFit[0]*(nonzeroy**2) + rightFit[1]*nonzeroy + rightFit[2] - margin)) & (nonzerox <
(rightFit[0]*(nonzeroy**2) + rightFit[1]*nonzeroy + rightFit[2] + margin)))
leftx = nonzerox[leftLaneInds]
lefty = nonzeroy[leftLaneInds]
rightx = nonzerox[rightLaneInds]
righty = nonzeroy[rightLaneInds]
leftFit = np.polyfit(lefty, leftx, 2)
rightFit = np.polyfit(righty, rightx, 2)
ploty = np.linspace(0, warpedFrame.shape[0]-1, warpedFrame.shape[0])
leftFitx = leftFit[0]*ploty**2 + leftFit[1]*ploty + leftFit[2]
rightFitx = rightFit[0]*ploty**2 + rightFit[1]*ploty + rightFit[2]
outImg = np.dstack((warpedFrame, warpedFrame, (warpedFrame)))*255
windowImg = np.zeros_like(outImg)
outImg[nonzeroy[leftLaneInds], nonzerox[leftLaneInds]] = [255, 0, 0]
outImg[nonzeroy[rightLaneInds], nonzerox[rightLaneInds]] = [0, 0, 255]
leftLineWindow1 = np.array([np.transpose(np.vstack([leftFitx-margin, ploty]))])
leftLineWindow2 = np.array([np.flipud(np.transpose(np.vstack([leftFitx+margin, ploty])))])
leftLinePts = np.hstack((leftLineWindow1, leftLineWindow2))
rightLineWindow1 = np.array([np.transpose(np.vstack([rightFitx-margin, ploty]))])
rightLineWindow2 = np.array([np.flipud(np.transpose(np.vstack([rightFitx+margin, ploty])))])
rightLinePts = np.hstack((rightLineWindow1, rightLineWindow2))
cv2.fillPoly(windowImg, np.int_([leftLinePts]), (0,255, 0))
cv2.fillPoly(windowImg, np.int_([rightLinePts]), (0,255, 0))
result = cv2.addWeighted(outImg, 1, windowImg, 0.3, 0)
figure, (ax1, ax2, ax3) = plt.subplots(3,1)
figure.set_size_inches(10, 10)
figure.tight_layout(pad=3.0)
ax1.imshow(imgrgb)
ax2.imshow(warpedFrame, cmap='gray')
ax3.imshow(result)
ax3.plot(leftFitx, ploty, color='yellow')
ax3.plot(rightFitx, ploty, color='yellow')
ax1.set_title("Original Frame")
ax2.set_title("Warped Frame")
ax3.set_title("Warped Frame With Search Window")
plt.show()
# Overlay lane lines on the original frame
warpZero = np.zeros_like(warpedFrame).astype(np.uint8)
colorWarp = np.dstack((warpZero, warpZero, warpZero))
ptsLeft = np.array([np.transpose(np.vstack([leftFitx, ploty]))])
ptsRight = np.array([np.flipud(np.transpose(np.vstack([rightFitx, ploty])))])
pts = np.hstack((ptsLeft, ptsRight))
cv2.fillPoly(colorWarp, np.int_([pts]), (0,255, 0))
newwarp = cv2.warpPerspective(colorWarp, invTransformationMatrix, (imgbgr.shape[1], imgbgr.shape[0]))
result = cv2.addWeighted(imgbgr, 1, newwarp, 0.3, 0)
figure, (ax1, ax2) = plt.subplots(2,1) # 2 rows, 1 column
figure.set_size_inches(10, 10)
figure.tight_layout(pad=3.0)
ax1.imshow(cv2.cvtColor(imgbgr, cv2.COLOR_BGR2RGB))
ax2.imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
ax1.set_title("Original Frame")
ax2.set_title("Original Frame With Lane Overlay")
plt.show()
# Calculate the road curvature in meters.
YMPERPIX = 10.0 / 1000
XMPERPIX = 3.7 / 781
yEval = np.max(ploty)
leftFitCr = np.polyfit(lefty * YMPERPIX, leftx * (XMPERPIX), 2)
rightFitCr = np.polyfit(righty * YMPERPIX, rightx * (XMPERPIX), 2)
leftCurvem = ((1 + (2*leftFitCr[0]*yEval*YMPERPIX + leftFitCr[1])**2)**1.5) / np.absolute(2*leftFitCr[0])
rightCurvem = ((1 + (2*rightFitCr[0]*yEval*YMPERPIX + rightFitCr[1])**2)**1.5) / np.absolute(2*rightFitCr[0])
print(f"Left lane curvature= {leftCurvem}m.")
print(f"Right lane curvature= {rightCurvem}m.")
print(f"The radius of curvature= {(leftCurvem+rightCurvem)/2}m.")
Left lane curvature= 46.986139537963645m. Right lane curvature= 3401.4743695444113m. The radius of curvature= 1724.2302545411874m.
# Calculate the position of the car relative to the center
carLocation = imgbgr.shape[1] / 2
height = imgbgr.shape[0]
bottomLeft = leftFit[0]*height**2 + leftFit[1]*height + leftFit[2]
bottomRight = rightFit[0]*height**2 + rightFit[1]*height + rightFit[2]
centerLane = (bottomRight - bottomLeft)/2 + bottomLeft
centerOffset = (np.abs(carLocation) - np.abs(centerLane)) * XMPERPIX
offsetStr = ""
if (centerOffset < 0):
offsetStr = "left of center"
elif (centerOffset > 0):
offsetStr = "right of center"
print(f"Center offset= {np.abs(centerOffset)}m {offsetStr}.")
Center offset= 0.05717200977740218m right of center.
# Display curvature and offset statistics on the image (Final image to be shown)
finalVersion = result.copy()
cv2.putText(finalVersion,'Curve Radius: '+str((leftCurvem+rightCurvem)/2)[:7]+'m', (int((5/600)*origImageSize[0]), int((
20/338)*origImageSize[1])), cv2.FONT_HERSHEY_SIMPLEX, (float((0.5/600)*origImageSize[0])),(255,255,255),2,cv2.LINE_AA)
offsetStr = ""
if (centerOffset < 0):
offsetStr = " Left of Center"
elif (centerOffset > 0):
offsetStr = " Right of Center"
cv2.putText(finalVersion,'Center Offset: '+str(np.abs(centerOffset))[:7]+'m'+offsetStr, (int((5/600)*origImageSize[0]), int((
40/338)*origImageSize[1])), cv2.FONT_HERSHEY_SIMPLEX, (float((0.5/600)*origImageSize[0])),(255,255,255),2,cv2.LINE_AA)
plt.imshow(cv2.cvtColor(finalVersion, cv2.COLOR_BGR2RGB))
plt.show()
# Load the image (test6)
filename = 'test6.jpg'
imgbgr = cv2.imread(filename)
origImageSize = imgbgr.shape[::-1][1:]
imgrgb = cv2.cvtColor(imgbgr, cv2.COLOR_BGR2RGB)
plt.imshow(imgrgb)
plt.show()
# change the image to binary color only black and white
hls = cv2.cvtColor(imgbgr, cv2.COLOR_BGR2HLS)
_, sxbinary = edge.threshold(hls[:, :, 1], thresh=(180, 255))
sxbinary = edge.blurGaussian(sxbinary, ksize=3)
sxbinary = edge.magThresh(sxbinary, sobelKernel=3, thresh=(110, 255))
sChannel = hls[:, :, 2]
_, sBinary = edge.threshold(sChannel, (20, 255))
_, rThresh = edge.threshold(imgbgr[:, :, 2], thresh=(180, 255))
rsBinary = cv2.bitwise_and(sBinary, rThresh)
laneLineMarkings = cv2.bitwise_or(rsBinary, sxbinary.astype(np.uint8))
plt.imshow(cv2.cvtColor(laneLineMarkings, cv2.COLOR_BGR2RGB))
plt.show()
# Place the region of interest (ROI) on the image
roiPoints = np.float32([
(570,460),
(213,684),
(1120,680),
(715,460)
])
imgbgrCopy = imgbgr.copy()
thisImage = cv2.polylines(imgbgrCopy, np.int32([roiPoints]), True, (147,20,255), 3)
plt.imshow(cv2.cvtColor(thisImage, cv2.COLOR_BGR2RGB))
plt.show()
desiredRoiPoints = np.float32([
[320, 0],
[320, origImageSize[1]],
[origImageSize[0]-320, origImageSize[1]],
[origImageSize[0]-320, 0]
])
transformationMatrix = cv2.getPerspectiveTransform(roiPoints, desiredRoiPoints)
invTransformationMatrix = cv2.getPerspectiveTransform(desiredRoiPoints, roiPoints)
warpedFrame = cv2.warpPerspective(laneLineMarkings, transformationMatrix, origImageSize, flags=(cv2.INTER_LINEAR))
(thresh, binaryWarped) = cv2.threshold(warpedFrame, 127, 255, cv2.THRESH_BINARY)
warpedFrame = binaryWarped.copy()
warpedPlot = cv2.polylines(binaryWarped, np.int32([desiredRoiPoints]), True, (147,20,255), 3)
plt.imshow(cv2.cvtColor(warpedPlot, cv2.COLOR_BGR2RGB))
plt.show()
histogram = np.sum(warpedFrame[int(warpedFrame.shape[0]/2):,:], axis=0)
figure, (ax1, ax2) = plt.subplots(2,1) # 2 row, 1 columns
figure.set_size_inches(10, 5)
ax1.imshow(warpedFrame, cmap='gray')
ax1.set_title("Warped Binary Frame")
ax2.plot(histogram)
ax2.set_title("Histogram Peaks")
plt.show()
# Get the indices of the lane line pixels using the sliding windows technique
margin = int((1/12) * origImageSize[0])
noOfWindows = 10
frameSlidingWindow = warpedFrame.copy()
windowHeight = np.int(warpedFrame.shape[0]/noOfWindows)
nonzero = warpedFrame.nonzero()
nonzeroy = np.array(nonzero[0])
nonzerox = np.array(nonzero[1])
leftLaneInds = []
rightLaneInds = []
midpoint = np.int(histogram.shape[0]/2)
leftxBase = np.argmax(histogram[:midpoint])
rightxBase = np.argmax(histogram[midpoint:]) + midpoint
leftxCurrent = leftxBase
rightxCurrent = rightxBase
for window in range(noOfWindows):
winYLow = warpedFrame.shape[0] - (window + 1) * windowHeight
winYHigh = warpedFrame.shape[0] - window * windowHeight
winXleftLow = leftxCurrent - margin
winXleftHigh = leftxCurrent + margin
winXrightLow = rightxCurrent - margin
winXrightHigh = rightxCurrent + margin
cv2.rectangle(frameSlidingWindow,(winXleftLow,winYLow),(winXleftHigh,winYHigh), (255,255,255), 2)
cv2.rectangle(frameSlidingWindow,(winXrightLow,winYLow),(winXrightHigh,winYHigh), (255,255,255), 2)
goodLeftInds = ((nonzeroy >= winYLow) & (nonzeroy < winYHigh) & (nonzerox >= winXleftLow) & (
nonzerox < winXleftHigh)).nonzero()[0]
goodRightInds = ((nonzeroy >= winYLow) & (nonzeroy < winYHigh) & (nonzerox >= winXrightLow) & (
nonzerox < winXrightHigh)).nonzero()[0]
leftLaneInds.append(goodLeftInds)
rightLaneInds.append(goodRightInds)
minpix = int((1/24) * origImageSize[0])
if len(goodLeftInds) > minpix:
leftxCurrent = np.int(np.mean(nonzerox[goodLeftInds]))
if len(goodRightInds) > minpix:
rightxCurrent = np.int(np.mean(nonzerox[goodRightInds]))
leftLaneInds = np.concatenate(leftLaneInds)
rightLaneInds = np.concatenate(rightLaneInds)
leftx = nonzerox[leftLaneInds]
lefty = nonzeroy[leftLaneInds]
rightx = nonzerox[rightLaneInds]
righty = nonzeroy[rightLaneInds]
leftFit = np.polyfit(lefty, leftx, 2)
rightFit = np.polyfit(righty, rightx, 2)
ploty = np.linspace(0, frameSlidingWindow.shape[0]-1, warpedFrame.shape[0])
leftFitx = leftFit[0]*ploty**2 + leftFit[1]*ploty + leftFit[2]
rightFitx = rightFit[0]*ploty**2 + rightFit[1]*ploty + rightFit[2]
outImg = np.dstack((frameSlidingWindow, frameSlidingWindow, (frameSlidingWindow))) * 255
outImg[nonzeroy[leftLaneInds], nonzerox[leftLaneInds]] = [255, 0, 0]
outImg[nonzeroy[rightLaneInds], nonzerox[rightLaneInds]] = [0, 0, 255]
figure, (ax1, ax2, ax3) = plt.subplots(3,1)
figure.set_size_inches(10, 10)
figure.tight_layout(pad=3.0)
ax1.imshow(imgrgb)
ax2.imshow(frameSlidingWindow, cmap='gray')
ax3.imshow(outImg)
ax3.plot(leftFitx, ploty, color='yellow')
ax3.plot(rightFitx, ploty, color='yellow')
ax1.set_title("Original Frame")
ax2.set_title("Warped Frame with Sliding Windows")
ax3.set_title("Detected Lane Lines with Sliding Windows")
plt.show()
# Use the lane line from the previous sliding window to get the parameters for the polynomial line for filling in the lane line
leftLaneInds = ((nonzerox > (leftFit[0]*(nonzeroy**2) + leftFit[1]*nonzeroy + leftFit[2] - margin)) & (nonzerox < (leftFit[0]*(
nonzeroy**2) + leftFit[1]*nonzeroy + leftFit[2] + margin)))
rightLaneInds = ((nonzerox > (rightFit[0]*(nonzeroy**2) + rightFit[1]*nonzeroy + rightFit[2] - margin)) & (nonzerox <
(rightFit[0]*(nonzeroy**2) + rightFit[1]*nonzeroy + rightFit[2] + margin)))
leftx = nonzerox[leftLaneInds]
lefty = nonzeroy[leftLaneInds]
rightx = nonzerox[rightLaneInds]
righty = nonzeroy[rightLaneInds]
leftFit = np.polyfit(lefty, leftx, 2)
rightFit = np.polyfit(righty, rightx, 2)
ploty = np.linspace(0, warpedFrame.shape[0]-1, warpedFrame.shape[0])
leftFitx = leftFit[0]*ploty**2 + leftFit[1]*ploty + leftFit[2]
rightFitx = rightFit[0]*ploty**2 + rightFit[1]*ploty + rightFit[2]
outImg = np.dstack((warpedFrame, warpedFrame, (warpedFrame)))*255
windowImg = np.zeros_like(outImg)
outImg[nonzeroy[leftLaneInds], nonzerox[leftLaneInds]] = [255, 0, 0]
outImg[nonzeroy[rightLaneInds], nonzerox[rightLaneInds]] = [0, 0, 255]
leftLineWindow1 = np.array([np.transpose(np.vstack([leftFitx-margin, ploty]))])
leftLineWindow2 = np.array([np.flipud(np.transpose(np.vstack([leftFitx+margin, ploty])))])
leftLinePts = np.hstack((leftLineWindow1, leftLineWindow2))
rightLineWindow1 = np.array([np.transpose(np.vstack([rightFitx-margin, ploty]))])
rightLineWindow2 = np.array([np.flipud(np.transpose(np.vstack([rightFitx+margin, ploty])))])
rightLinePts = np.hstack((rightLineWindow1, rightLineWindow2))
cv2.fillPoly(windowImg, np.int_([leftLinePts]), (0,255, 0))
cv2.fillPoly(windowImg, np.int_([rightLinePts]), (0,255, 0))
result = cv2.addWeighted(outImg, 1, windowImg, 0.3, 0)
figure, (ax1, ax2, ax3) = plt.subplots(3,1)
figure.set_size_inches(10, 10)
figure.tight_layout(pad=3.0)
ax1.imshow(imgrgb)
ax2.imshow(warpedFrame, cmap='gray')
ax3.imshow(result)
ax3.plot(leftFitx, ploty, color='yellow')
ax3.plot(rightFitx, ploty, color='yellow')
ax1.set_title("Original Frame")
ax2.set_title("Warped Frame")
ax3.set_title("Warped Frame With Search Window")
plt.show()
# Overlay lane lines on the original frame
warpZero = np.zeros_like(warpedFrame).astype(np.uint8)
colorWarp = np.dstack((warpZero, warpZero, warpZero))
ptsLeft = np.array([np.transpose(np.vstack([leftFitx, ploty]))])
ptsRight = np.array([np.flipud(np.transpose(np.vstack([rightFitx, ploty])))])
pts = np.hstack((ptsLeft, ptsRight))
cv2.fillPoly(colorWarp, np.int_([pts]), (0,255, 0))
newwarp = cv2.warpPerspective(colorWarp, invTransformationMatrix, (imgbgr.shape[1], imgbgr.shape[0]))
result = cv2.addWeighted(imgbgr, 1, newwarp, 0.3, 0)
figure, (ax1, ax2) = plt.subplots(2,1) # 2 rows, 1 column
figure.set_size_inches(10, 10)
figure.tight_layout(pad=3.0)
ax1.imshow(cv2.cvtColor(imgbgr, cv2.COLOR_BGR2RGB))
ax2.imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
ax1.set_title("Original Frame")
ax2.set_title("Original Frame With Lane Overlay")
plt.show()
# Calculate the road curvature in meters.
YMPERPIX = 10.0 / 1000
XMPERPIX = 3.7 / 781
yEval = np.max(ploty)
leftFitCr = np.polyfit(lefty * YMPERPIX, leftx * (XMPERPIX), 2)
rightFitCr = np.polyfit(righty * YMPERPIX, rightx * (XMPERPIX), 2)
leftCurvem = ((1 + (2*leftFitCr[0]*yEval*YMPERPIX + leftFitCr[1])**2)**1.5) / np.absolute(2*leftFitCr[0])
rightCurvem = ((1 + (2*rightFitCr[0]*yEval*YMPERPIX + rightFitCr[1])**2)**1.5) / np.absolute(2*rightFitCr[0])
print(f"Left lane curvature= {leftCurvem}m.")
print(f"Right lane curvature= {rightCurvem}m.")
print(f"The radius of curvature= {(leftCurvem+rightCurvem)/2}m.")
Left lane curvature= 102.51359188716613m. Right lane curvature= 61.14532811822909m. The radius of curvature= 81.8294600026976m.
# Calculate the position of the car relative to the center
carLocation = imgbgr.shape[1] / 2
height = imgbgr.shape[0]
bottomLeft = leftFit[0]*height**2 + leftFit[1]*height + leftFit[2]
bottomRight = rightFit[0]*height**2 + rightFit[1]*height + rightFit[2]
centerLane = (bottomRight - bottomLeft)/2 + bottomLeft
centerOffset = (np.abs(carLocation) - np.abs(centerLane)) * XMPERPIX
offsetStr = ""
if (centerOffset < 0):
offsetStr = "left of center"
elif (centerOffset > 0):
offsetStr = "right of center"
print(f"Center offset= {np.abs(centerOffset)}m {offsetStr}.")
Center offset= 0.15527635172854296m left of center.
# Display curvature and offset statistics on the image (Final image to be shown)
finalVersion = result.copy()
cv2.putText(finalVersion,'Curve Radius: '+str((leftCurvem+rightCurvem)/2)[:7]+'m', (int((5/600)*origImageSize[0]), int((
20/338)*origImageSize[1])), cv2.FONT_HERSHEY_SIMPLEX, (float((0.5/600)*origImageSize[0])),(255,255,255),2,cv2.LINE_AA)
offsetStr = ""
if (centerOffset < 0):
offsetStr = " Left of Center"
elif (centerOffset > 0):
offsetStr = " Right of Center"
cv2.putText(finalVersion,'Center Offset: '+str(np.abs(centerOffset))[:7]+'m'+offsetStr, (int((5/600)*origImageSize[0]), int((
40/338)*origImageSize[1])), cv2.FONT_HERSHEY_SIMPLEX, (float((0.5/600)*origImageSize[0])),(255,255,255),2,cv2.LINE_AA)
plt.imshow(cv2.cvtColor(finalVersion, cv2.COLOR_BGR2RGB))
plt.show()